﻿
#include <vector>
#include <string>
#include <hpdf.h>
#include <locale>
#include <codecvt>
#include <iostream>
#include <fstream>
using namespace std;
// 生成所有常用汉字的字符串
std::string getAllChineseCharacters() {
	std::string chinese_chars;
	// Unicode范围
	for (wchar_t c = 0x4E00; c <= 0x9FFF; ++c) {
		chinese_chars += std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(c);
	}
	return chinese_chars;
}

class PDFGenerator {
private:
	HPDF_Doc pdf;
	HPDF_Font font;
	HPDF_Page current_page;
	const float margin_x = 50.0f;
	const float margin_y = 50.0f;
	const int max_chars_per_line = 45;
	const int max_lines_per_page = 20;
	float page_width;
	float page_height;

	// 字体路径列表
	const std::vector<std::string> font_paths = {
		"./simsun.ttf"
	};

	static void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void* user_data) {
		std::cerr << "PDF错误: " << error_no << ", 详细信息: " << detail_no << std::endl;
		throw std::runtime_error("PDF生成过程中发生错误");
	}

	bool load_font() {
		for (const auto& path : font_paths) {
			std::cout << "尝试加载字体文件: " << path << std::endl;

			if (std::ifstream(path).good()) {
				std::cout << "文件存在，正在加载..." << std::endl;

				const char* font_name = HPDF_LoadTTFontFromFile(pdf, path.c_str(), HPDF_TRUE);
				if (font_name) {
					std::cout << "字体名称加载成功: " << font_name << std::endl;

					font = HPDF_GetFont(pdf, font_name, "UTF-8");
					if (font) {
						std::cout << "成功加载字体: " << path << std::endl;
						return true;
					}
					else {
						std::cout << "HPDF_GetFont 失败" << std::endl;
					}
				}
				else {
					std::cout << "HPDF_LoadTTFontFromFile 失败" << std::endl;
				}
			}
			else {
				std::cout << "文件不存在或无法读取: " << path << std::endl;
			}
		}
		return false;
	}

	void create_new_page() {
		current_page = HPDF_AddPage(pdf);
		HPDF_Page_SetSize(current_page, HPDF_PAGE_SIZE_A4, HPDF_PAGE_PORTRAIT);
		page_width = HPDF_Page_GetWidth(current_page);
		page_height = HPDF_Page_GetHeight(current_page);
		HPDF_Page_SetFontAndSize(current_page, font, 12);
	}

	void write_text_line(const std::string& line, float& y_pos) {
		HPDF_Page_BeginText(current_page);
		HPDF_Page_TextOut(current_page, margin_x, y_pos, line.c_str());
		HPDF_Page_EndText(current_page);
		y_pos -= 18.0f;  // 行间距
	}

public:
	PDFGenerator() : pdf(nullptr), font(nullptr), current_page(nullptr) {
		pdf = HPDF_New(error_handler, nullptr);
		if (!pdf) {
			throw std::runtime_error("无法创建PDF对象");
		}

		// 设置UTF-8编码
		HPDF_UseUTFEncodings(pdf);
		HPDF_SetCurrentEncoder(pdf, "UTF-8");
	}

	~PDFGenerator() {
		if (pdf) {
			HPDF_Free(pdf);
		}
	}

	void generate(const std::string& text, const std::string& output_file) {
		try {
			// 设置文档信息
			HPDF_SetInfoAttr(pdf, HPDF_INFO_TITLE, "中文PDF文档");
			HPDF_SetInfoAttr(pdf, HPDF_INFO_AUTHOR, "PDF生成器");

			// 加载字体
			if (!load_font()) {
				throw std::runtime_error("无法加载任何字体文件");
			}

			// 创建第一页
			create_new_page();

			// 计算每页最大字符数
			const int max_chars_per_page = max_chars_per_line * max_lines_per_page;

			// 分页处理文本
			size_t start_pos = 0;
			float y_pos = page_height - margin_y;

			while (start_pos < text.length()) {
				std::string page_text = text.substr(start_pos, max_chars_per_page);
				size_t line_pos = 0;

				for (int line = 0; line < max_lines_per_page; ++line) {
					if (line_pos >= page_text.length()) break;

					std::string line_text = page_text.substr(line_pos, max_chars_per_line);
					write_text_line(line_text, y_pos);
					line_pos += max_chars_per_line;
				}

				start_pos += max_chars_per_page;
				if (start_pos < text.length()) {
					create_new_page();
					y_pos = page_height - margin_y;
				}
			}

			// 保存文件
			HPDF_SaveToFile(pdf, output_file.c_str());
			std::cout << "PDF生成成功:" << output_file << std::endl;

		}
		catch (const std::exception& e) {
			throw std::runtime_error(std::string("PDF生成失败: ") + e.what());
		}
	}
};

int main() {
	try {
		PDFGenerator generator;
		std::string text = getAllChineseCharacters(); // 获取所有汉字
		generator.generate(text, "output.pdf");
		return 0;
	}
	catch (const std::exception& e) {
		std::cerr << "错误: " << e.what() << std::endl;
		return 1;
	}
}